home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / ms-0.07 / mslaved / mslavedc.c < prev   
C/C++ Source or Header  |  1995-06-26  |  7KB  |  298 lines

  1. /* mslavedc.c - MandelSpawn computation server control program */
  2. /* (named in accordance with timedc, etc.). */
  3.  
  4. /*  
  5.     This file is part of MandelSpawn, a network Mandelbrot program.
  6.  
  7.     Copyright (C) 1990-1993 Andreas Gustafsson
  8.  
  9.     MandelSpawn is free software; you can redistribute it and/or modify
  10.     it under the terms of the GNU General Public License, version 1,
  11.     as published by the Free Software Foundation.
  12.  
  13.     MandelSpawn is distributed in the hope that it will be useful,
  14.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.     GNU General Public License for more details.
  17.  
  18.     You should have received a copy of the GNU General Public License,
  19.     version 1, along with this program; if not, write to the Free 
  20.     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22.  
  23. #include <stdio.h>
  24. #include <errno.h>
  25. #include <fcntl.h>
  26. #include <sys/ioctl.h>
  27. #include <signal.h>
  28.  
  29. /*
  30.   The only system I know needs the following two #includes is SCO Unix, 
  31.   which needs them to define FNDELAY.  If they cause trouble with your
  32.   system, just remove them.
  33. */
  34. #include <sys/types.h>
  35. #include <sys/file.h>
  36.  
  37. /* This is for Linux */
  38. #ifndef FNDELAY
  39. #ifdef O_NDELAY
  40. #define FNDELAY O_NDELAY
  41. #endif
  42. #endif
  43.  
  44. #include "datarep.h"
  45. #include "ms_ipc.h"
  46.  
  47. #define RETRIES 5 /* how many times to retry getting a PID in ping() */
  48.  
  49. extern int errno; /* 4.3BSD needs this even when errno.h is included */
  50.  
  51. char *me;             /* name of program */
  52. int port = DEFAULT_PORT;    /* UDP port */
  53. char *command = NULL;
  54.  
  55. int kill_mode = 0;
  56.  
  57. int timeout_supplied = 0;    /* true if user gave a timeout option */
  58.  
  59.  
  60. /* Report a fatal error and exit */
  61.  
  62. void error(s)
  63.      char *s;
  64. { fprintf(stderr, "%s: ", me);
  65.   perror(s);
  66.   exit(1);
  67. }
  68.  
  69.  
  70. /*
  71.   Repeatedly send datagrams to "host" trying to find out the pid of 
  72.   an existing server, if any.  Returns the pid, or 0 if no response.
  73. */
  74.  
  75. int ping(host)
  76.      char *host;
  77. { int i;
  78.   int status;
  79.   WhoAreYouMessage out;
  80.   Message in;
  81.   int osock, isock;
  82.   struct sockaddr_in oname, iname, mname;
  83.   int mnamelen;
  84.   struct hostent *hp, *gethostbyname();
  85.   /* set up the output socket; use an arbitrary port */
  86.   osock=socket(AF_INET, SOCK_DGRAM, 0);
  87.   if(osock<0)
  88.   { error("opening output socket");
  89.   }
  90.   hp=gethostbyname(host);
  91.   if(hp==0)
  92.   { error("unknown host");
  93.   }
  94.   /* set up the destination address */
  95.   oname.sin_family=AF_INET;
  96.   oname.sin_port=htons(port);
  97.   bcopy(hp->h_addr, (char *)&oname.sin_addr, hp->h_length);
  98.   isock=socket(AF_INET, SOCK_DGRAM, 0);
  99.   if(isock<0)
  100.   { error("opening input socket");
  101.   }
  102.   iname.sin_family=AF_INET;
  103.   iname.sin_addr.s_addr=INADDR_ANY;
  104.   iname.sin_port=0;
  105.   if(bind(isock, &iname, (int) sizeof(iname)))
  106.   { error("binding input socket");
  107.   }
  108.   if(fcntl(isock, F_SETFL, FNDELAY) == -1)
  109.   { error("unblocking socket");
  110.   }
  111.   mnamelen=sizeof(mname);
  112.   if(getsockname(isock, &mname, &mnamelen)== -1)
  113.     error("getsockname");
  114.   out.header.magic=htons(MAGIC);
  115.   out.header.version=htons(VERSION);
  116.   out.header.type=htons(WHO_R_U_MESSAGE);
  117.   out.port=mname.sin_port; /* in network byte order already */
  118.   for(i=0; i<RETRIES; i++)
  119.   { int nbytes;
  120.     int fromlen;
  121.     if(sendto(osock, (char *)&out, sizeof(WhoAreYouMessage), 0,
  122.           (struct sockaddr *)&oname, sizeof(oname)) < 0)
  123.       error("sending pid inquiry message");
  124.     /*
  125.       This previously used read(), but some non-BSD TCP/IP implementations
  126.       don't allow it to be used with connectionless sockets.  Also,
  127.       while the Sun implementation does allow for a null pointer
  128.       for the "from" argument in recvfrom(), the "fromlen" argument
  129.       may not be a null pointer.
  130.     */
  131.     nbytes = recvfrom(isock, (char *) &in, sizeof(in),
  132.               0, (struct sockaddr *) 0, &fromlen);
  133.       if(nbytes == 0
  134. #ifdef EWOULDBLOCK
  135.      || (nbytes == -1 && errno == EWOULDBLOCK)
  136. #endif
  137.     )
  138.       {    /* no reply yet */
  139.     sleep(1);
  140.       }
  141.       else if(nbytes == -1)
  142.       {    error("receiving pid info");
  143.       }
  144.       else /* got a reply */
  145.       {    status=ntohs(in.iam.pid);
  146.     goto done;
  147.       }
  148.   }
  149.   status=0; /* unsuccessful */
  150.  done:
  151.   (void) close(osock);
  152.   (void) close(isock);
  153.   return(status);
  154. }
  155.  
  156.  
  157. /* 
  158.   Kill any server that is already active in this machine.
  159.   Return 0 if successful kill, 1 if no response.
  160. */
  161.   
  162. int murder()
  163. { int pid;
  164.   char my_name[256];
  165.   if(gethostname(my_name, sizeof(my_name)) == 1)
  166.     error("gethostname");
  167.   pid=ping(my_name); /* get pid of existing server, if any */
  168.   if(pid==0)
  169.     return(1); /* return failed exit status */
  170.   if(kill(pid, SIGTERM)== -1) 
  171.     error("kill");
  172.   return(0);
  173. }
  174.  
  175. /* argument list for mslaved */
  176. static char *arglist[16];         /* more than enough */
  177. static char **arglistp = arglist+1;    /* pointer to the above */
  178.  
  179. void copy_arg(p)
  180.      char *p;
  181. { *arglistp++ = p;
  182. }
  183.  
  184. /* Set up the file handles and exec an mslaved */
  185.  
  186. void birth()
  187. { int isock;
  188.   struct sockaddr_in iname;
  189.   int tty;
  190.   int i;
  191.  
  192.   /* set up the socket */
  193.   isock=socket(AF_INET, SOCK_DGRAM, 0);
  194.   if(isock<0)
  195.   { error("opening socket");
  196.   }
  197.   iname.sin_family=AF_INET;
  198.   iname.sin_addr.s_addr=INADDR_ANY;
  199.   iname.sin_port=htons(port);
  200.   if(bind(isock, &iname, (int) sizeof(iname)) == -1) 
  201.   { /* probable cause of error is that the port is in use */
  202.     error("binding socket");
  203.   }
  204.   
  205.   /* dup the newly-opened socket to stdin */
  206.   close(0);
  207.   dup(isock);
  208.  
  209. #ifdef TIOCNOTTY /* presumably BSD-like */
  210.   if((tty=open("/dev/tty", 0, 0)) != -1)
  211.   { ioctl(tty, TIOCNOTTY, (struct sgttyb *) 0);
  212.     (void) close(tty);
  213.   }
  214.   else
  215.   { if(setpgrp(0, 0)) 
  216.       error("setpgrp");
  217.   }
  218. #else /* presumably SYSV-like */
  219.   setpgrp();
  220. #endif
  221.  
  222.   for(i=1; i<10; i++)
  223.     (void) close(i);
  224.   
  225.   arglist[0] = command;
  226.  
  227.   /* supply a default timeout if none was given */
  228.   if(!timeout_supplied)
  229.     copy_arg("-t900");
  230.       
  231.   copy_arg((char *) 0);
  232.   execvp(command, arglist);
  233.   exit(1); /* there's no good way to report errors here */
  234. }
  235.  
  236.  
  237. int main(argc, argv)
  238.      int argc; char **argv;
  239. { char *s;
  240.  
  241.   me=argv[0];
  242.   for(;s = *++argv, --argc;)
  243.   { if(*s != '-')
  244.     { command = s;
  245.     }
  246.     else
  247.     { switch(s[1])
  248.       {    
  249.       case 'k': /* kill */
  250.     kill_mode++;
  251.     break;
  252.       case 'q': /* query */
  253.     { int rpid = ping(s[2] ? s+2 : (--argc, *++argv));
  254.       if(rpid) 
  255.       { printf("%d\n", rpid);
  256.         exit(0);
  257.       }
  258.       else
  259.         exit(1);
  260.     }
  261.       case 't': /* timeout */
  262.     timeout_supplied = 1;
  263.     /* fallthrough */
  264.       case 'n': /* nice */
  265.     /* copy these options and possible separate option arguments to */
  266.     /* the mslaved argument list */
  267.     copy_arg(s);
  268.     if(! s[2])
  269.       copy_arg((--argc, *++argv));
  270.     break;
  271.       case 'p': /* port */
  272.     port = atoi(s[2] ? s+2 : (--argc, *++argv));
  273.     break;
  274.       default: 
  275.     goto usage;
  276.       }
  277.     }
  278.   }
  279.  
  280.   if(kill_mode) 
  281.     exit(murder());
  282.  
  283.   if(!command)
  284.     error("missing command");
  285.  
  286.   switch(fork())
  287.   { case -1:
  288.       error("fork");
  289.     case 0: /* child */
  290.       birth();
  291.     default: /* parent */
  292.       exit(0);
  293.   }
  294.  usage:
  295.   fprintf(stderr, "usage: %s [-k] [-q] [-nnice] [-ttimeout] [-pport]\n", me);
  296.   exit(1);
  297. }
  298.